package cn.com.nes.common.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

public class JwtUtil {

	private final static String SHOP_HOST = "shop.nes.cn";

	private static final String SHOP_SECRET = "e94ce1c8dd9a1cd94e1d7ee89ace88b5";

	/**
     * 由字符串生成加密key
     * @return
     */
    public SecretKey generalKey(){
        String stringKey = "nes123456,";//本地配置文件中加密的密文7786df7fc3a34e26a61c034d5ec8245d
        byte[] encodedKey = Base64.decodeBase64(stringKey);//本地的密码解码[B@152f6e2
        //System.out.println(encodedKey);//[B@152f6e2
        //System.out.println(Base64.encodeBase64URLSafeString(encodedKey));//7786df7fc3a34e26a61c034d5ec8245d
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");// 根据给定的字节数组使用AES加密算法构造一个密钥，使用 encodedKey中的始于且包含 0 到前 leng 个字节这是当然是所有。（后面的文章中马上回推出讲解Java加密和解密的一些算法）
        return key;
    }
    
    /**
     * 解密jwt
     * @param jwt
     * @return
     * @throws Exception
     */
    public Claims parseJWT(String jwt) throws Exception{
        SecretKey key = generalKey();  //签名秘钥，和生成的签名的秘钥一模一样
        Claims claims = Jwts.parser()  //得到DefaultJwtParser
           .setSigningKey(key)         //设置签名的秘钥
           .parseClaimsJws(jwt).getBody();//设置需要解析的jwt
        return claims;
    }
    
	public String createJWT(String id, String subject, long ttlMillis)  {
		try {
			SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; //指定签名的时候使用的签名算法，也就是header那部分，jjwt已经将这部分内容封装好了。
	        long nowMillis = System.currentTimeMillis();//生成JWT的时间
	        Date now = new Date(nowMillis);
	        Map<String,Object> claims = new HashMap<String,Object>();//创建payload的私有声明（根据特定的业务需要添加，如果要拿这个做验证，一般是需要和jwt的接收方提前沟通好验证方式的）
	        //claims.put("uid", "DSSFAWDWADAS...");
	       // claims.put("user_name", "admin");
	       // claims.put("nick_name","DASDA121");
	        SecretKey key = generalKey();//生成签名的时候使用的秘钥secret,这个方法本地封装了的，一般可以从本地配置文件中读取，切记这个秘钥不能外露哦。它就是你服务端的私钥，在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
	        //下面就是在为payload添加各种标准声明和私有声明了
	        JwtBuilder builder = Jwts.builder() //这里其实就是new一个JwtBuilder，设置jwt的body
	                .setClaims(claims)          //如果有私有声明，一定要先设置这个自己创建的私有的声明，这个是给builder的claim赋值，一旦写在标准的声明赋值之后，就是覆盖了那些标准的声明的
	                .setId(id)                  //设置jti(JWT ID)：是JWT的唯一标识，根据业务需要，这个可以设置为一个不重复的值，主要用来作为一次性token,从而回避重放攻击。
	                .setIssuedAt(now)           //iat: jwt的签发时间
	                .setIssuer("adminuser")
	                .setSubject(subject)        //sub(Subject)：代表这个JWT的主体，即它的所有人，这个是一个json格式的字符串，可以存放什么userid，roldid之类的，作为什么用户的唯一标志。
	                .signWith(signatureAlgorithm, key);//设置签名使用的签名算法和签名使用的秘钥
	        if (ttlMillis >= 0) {
	            long expMillis = nowMillis + ttlMillis;
	            Date exp = new Date(expMillis);
	            builder.setExpiration(exp);     //设置过期时间
	        }
	        return builder.compact();           //就开始压缩为xxxxxxxxxxxxxx.xxxxxxxxxxxxxxx.xxxxxxxxxxxxx这样的jwt
		} catch (Exception e) {
			e.printStackTrace();
			return null ;
		}
     }

	public String createShopJWT(int id)  {
		try {
			SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
			Map<String, Object> header = new LinkedHashMap<String, Object>();
			Map<String,Object> claims = new LinkedHashMap<String,Object>();
			SecretKey key = new SecretKeySpec(SHOP_SECRET.getBytes(), "HS256");

			header.put("typ", "JWT");
			header.put("alg", "HS256");

			Long now = System.currentTimeMillis() / 1000;
			claims.put("iss", SHOP_HOST);
			claims.put("aud", SHOP_HOST);
			claims.put("iat", now);
			claims.put("nbf", now);
			claims.put("exp", now + 3600 * 24 * 365);
			claims.put("jti", new Object[]{id, "user"});

			JwtBuilder builder = Jwts.builder()
					.setHeader(header)
					.setClaims(claims)
					.signWith(signatureAlgorithm, key);

			return builder.compact();
		} catch (Exception e) {
			e.printStackTrace();
			return null ;
		}
	}

	/**
	 * 由字符串生成加密key
	 * @return
	 */
	public static SecretKey generalWXKey() {
		String stringKey = "nes123456,";//本地配置文件中加密的密文7786df7fc3a34e26a61c034d5ec8245d
		byte[] encodedKey = Base64.decodeBase64(stringKey);//本地的密码解码[B@152f6e2
		SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");// 根据给定的字节数组使用AES加密算法构造一个密钥，使用 encodedKey中的始于且包含 0 到前 leng 个字节这是当然是所有。（后面的文章中马上回推出讲解Java加密和解密的一些算法）
		return key;
	}

	/**
	 * 解密jwt
	 * @param jwt
	 * @return
	 */
	public static Claims parseWXJWT(String jwt) throws Exception {
		SecretKey key = generalWXKey();  //签名秘钥，和生成的签名的秘钥一模一样
		Claims claims = Jwts.parser()  //得到DefaultJwtParser
				.setSigningKey(key)         //设置签名的秘钥
				.parseClaimsJws(jwt).getBody();//设置需要解析的jwt
		return claims;
	}
	
	/**
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {
		final JwtUtil jwtUtil = new JwtUtil();
		final Claims claims = jwtUtil.parseJWT("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ7XCJpc0F1dGhvclJvbGVcIjpcIjBcIixcInJvbGVOYW1lXCI6XCLnianogZTnvZFcIixcIm5lc19jb21wYW55SWRcIjpcIk5FUzEwMDAzNFwiLFwiY29tcGFueU5hbWVcIjpcIuWIm-S4lue6qu-8iOa1i-ivleWFrOWPuO-8iVwiLFwiY29tcGFueVR5cGVcIjpcIjAxXCIsXCJjb21wYW55VHlwZU5hbWVcIjpcIuWOguWVhlwiLFwiaXNDZXJ0XCI6MCxcImlkXCI6NjU5LFwidXVpZFwiOlwiZDdjZTBlOWQtMDY4Zi00ZGY5LTg5MzQtNWQ3MmIyNzIyY2FlXCIsXCJ1c2VybmFtZVwiOlwiMTU1MTIzNDU2NzhcIixcInBhc3N3b3JkXCI6XCIxMjM0NTZcIixcInNleFwiOlwiMDFcIixcIm5pY2tOYW1lXCI6XCLliJvkuJbnuqpcIixcInJvbGVfaWRcIjpcIjY4OTI2Mjk4LTUyMWMtNDYzYi05MmVkLTAxNzYyN2JjMmNkYlwiLFwiYXJlYWNvZGVcIjpcIjExXCIsXCJhcmVhbmFtZVwiOlwi5YyX5LqsXCIsXCJjb21wYW55SWRcIjpcIjAwMDAwMDM4XCIsXCJkZXBhcnRtZW50SWRcIjpcIjAwMDAwMDM4RDAwMVwiLFwidXNlclR5cGVcIjpcIjA0XCIsXCJwaG9uZVwiOlwiMTU1MTIzNDU2NzhcIixcImNyZWF0ZVVpZFwiOjEzMSxcImNyZWF0ZVRpbWVcIjpcIk1hciAyMSwgMjAyMyAxMDo0MTowNCBBTVwiLFwibW9kaWZ5VWlkXCI6MTMxLFwibW9kaWZ5VGltZVwiOlwiTWFyIDIxLCAyMDIzIDEwOjQxOjA0IEFNXCIsXCJzZnNjXCI6MCxcImlzT25saW5lUmVnXCI6MH0iLCJpc3MiOiJhZG1pbnVzZXIiLCJleHAiOjE3MTQ3Mjk5MDIsImlhdCI6MTY4MzE5MzkwMiwianRpIjoiMTU1MTIzNDU2NzgifQ.rgr5odS8fZ9N1T0gkNsCWp3h_SUylrPzbCGRZKey5z8");
		System.out.println(claims.getSubject());
	}

}

